﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace OrderGeneratorService
{
   public class AsyncStateInfo
   {
      public Socket socket;
      public byte[] dataBuffer = new byte[512];
      public AsyncStateInfo(Socket sock)
      {
         socket = sock;
      }
   }


   class QuoteServerAsync
   {
      //Order order;
      Socket mdpSocket;
      Socket mdcSocket;
      Socket tcpSocket;
      byte[] receiveBuffer;

      public QuoteServerAsync()
      {
         receiveBuffer = new byte[512];
      }
      public void Start()
      {
         ManualResetEvent shutDownSignal = new ManualResetEvent(false);
         //Generator gen = new Generator();

         //IP Multicast address
         //IPAddress groupAddress = IPAddress.Parse("224.5.6.7");
         //IPEndPoint mcastEP = new IPEndPoint(groupAddress, 30002);
         mdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);




         IPEndPoint localEP = new IPEndPoint(IPAddress.Loopback, 20000);
         Console.WriteLine("Market-Data Producer Service Started - (Using MultiCast)");
         Console.WriteLine("Waiting for service input ... ");
         tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         tcpSocket.Bind(localEP);
         tcpSocket.Listen(10);
         tcpSocket.BeginAccept(new AsyncCallback(AcceptConnection), new AsyncStateInfo(tcpSocket));
         shutDownSignal.WaitOne();


         


         //byte[] sendBuffer = new byte[512];
         //sendBuffer = Encoding.ASCII.GetBytes(mktPrice);

         //Set multicast TTL
         //mdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 3);
         //Send data to multicast address
         //mdpSocket.SendTo(sendBuffer, mcastEP);
         //mdpSocket.Close();
         Console.WriteLine("Market Data sent to group of consumers");
         Console.Read();
      }



      public static void AcceptConnection(IAsyncResult result)
      {
         Order order;
         Generator gen = new Generator();

         Console.WriteLine("Connection Request Thread : " + Thread.CurrentThread.GetHashCode());
         AsyncStateInfo stateInfo = result.AsyncState as AsyncStateInfo;
         //Accepts client connection
         Socket mdcSocket = stateInfo.socket.EndAccept(result);
         //Starts listening to client connection
         stateInfo.socket.BeginAccept(new AsyncCallback(AcceptConnection), new AsyncStateInfo(stateInfo.socket));
         AsyncStateInfo mdcStateInfo = new AsyncStateInfo(mdcSocket);
         byte[] rBuf = new byte[512];

         EndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 20000);
         int bytesReceived = stateInfo.socket.ReceiveFrom(rBuf, ref endPoint);
         IPEndPoint mdpEndPoint = (IPEndPoint)endPoint;
         string ser = Encoding.ASCII.GetString(rBuf, 0, bytesReceived);
         order = gen.generateOrder(ser);
         string mktPrice = order.ToString();
         Console.WriteLine(mktPrice);
         
         
         //Starts listening to client connection
         //stateInfo.socket.BeginAccept(new AsyncCallback(AcceptConnection), new AsyncStateInfo(stateInfo.socket));
         //AsyncStateInfo mdcStateInfo = new AsyncStateInfo(mdcSocket);
         //string mktPrice = "MSFT;25,IBM;24";
         byte[] dataBuf = Encoding.ASCII.GetBytes(mktPrice);

         //copy data buffer
         Buffer.BlockCopy(dataBuf, 0, mdcStateInfo.dataBuffer, 0, dataBuf.Length);

         IPAddress groupAddress = IPAddress.Parse("224.5.6.7");
         IPEndPoint mcastEP = new IPEndPoint(groupAddress, 30002);
         //Set multicast TTL
         mdcSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 3);
         //Sends data asynchronously
         mdcSocket.BeginSendTo(mdcStateInfo.dataBuffer, 0, 512, SocketFlags.Multicast, mcastEP,
            new AsyncCallback(SendData), mdcStateInfo);
      }


      public static void SendData(IAsyncResult result)
      {
         Console.WriteLine("Data Sending Thread : " + Thread.CurrentThread.GetHashCode());
         AsyncStateInfo stateInfo = result.AsyncState as AsyncStateInfo;
         //Completes asynchronous send
         stateInfo.socket.EndSend(result);
      }
   }
}
